#include "from_xml.h"

#include <QDomElement>
#include <QStringList>

#include "rows.h"
#include "columns.h"
#include "model_class.h"


namespace BitWin
{


// Anonymous namespace for internal usage staff
namespace
{


BitRange str2range(const QString& s)
{
    QStringList list(s.split(":", QString::SkipEmptyParts));
    if (list.size() == 1)
    {
        bool conv_ok = false;
        unsigned val = list[0].toUInt(&conv_ok, 10);
        if (conv_ok)
            return BitRange(val, val);
    }
    else if (list.size() == 2)
    {
        bool fst_ok(false), last_ok(false);
        unsigned fst = list[0].toUInt(&fst_ok, 10);
        unsigned last = list[1].toUInt(&last_ok, 10);
        if (fst_ok && last_ok)
            return BitRange(fst, last);
    }
    
    return BitRange();
}

PRowList makeRows(const QDomElement& element)
{
    PRowList rows;
    unsigned word_no = 0;
        
    // HACK! What if num. of "rows" elements > 1?
    QDomElement rows_element(element.firstChildElement("rows"));
    
    for (
        QDomElement e(rows_element.firstChildElement());
        !e.isNull();
        e = e.nextSiblingElement()
    )
    {
        if (e.tagName() == "header")
            rows << PRow(FromXml::makeHeaderRow(e));
        else if (e.tagName() == "word")
        {
            rows << PRow(FromXml::makeWordRow(e, word_no));
            
            for (
                QDomElement f(e.firstChildElement("field"));
                !f.isNull();
                f = f.nextSiblingElement("field")
            )
                rows << PRow(FromXml::makeFieldRow(f, word_no));
            
            ++word_no;
        }
    }
    
    return rows;
}

PColumnList makeColumns(const QDomElement& element)
{
    PColumnList columns;
    
    // HACK! What if num. of "columns" elements > 1?
    QDomElement columns_element(element.firstChildElement("columns"));
    
    for (
        QDomElement e(columns_element.firstChildElement("column"));
        !e.isNull();
        e = e.nextSiblingElement("column")
    )
        columns << PColumn(FromXml::makeBitsColumn(e));
    
    return columns;
}


} // Anonymous namespace end


HeaderRow* FromXml::makeHeaderRow(const QDomElement& element)
{
    return new HeaderRow(element.attribute("title"));
}

WordRow* FromXml::makeWordRow(
    const QDomElement& element, const int word_no
)
{
    return new WordRow(element.attribute("title"), word_no);
}

FieldRow* FromXml::makeFieldRow(
    const QDomElement& element, const int word_no
)
{
    return new FieldRow(
        element.attribute("title"),
        str2range(element.attribute("bits")),
        word_no
    );
}

BitsColumn* FromXml::makeBitsColumn(const QDomElement& element)
{
    return new BitsColumn(
        element.attribute("title"),
        str2range(element.attribute("bits"))
    );
}

Model* FromXml::makeModel(const QDomElement& element)
{
    return new Model(
        makeRows(element),
        makeColumns(element)
    );
}


} // BitWin namespace end
